<template>
    <div class="clearfix">
        <a-upload
            v-model:file-list="fileList"
            list-type="picture-card"
            v-bind="{ ...$attrs, ...$props }"
            :before-upload="beforeUpload"
            @preview="handlePreview"
            @change="handleChange"
        >
        <div v-if="fileList && fileList.length < props?.maxCount">
            <PlusOutlined />
            <div style="margin-top: 8px">上传</div>
        </div>
        </a-upload>
        <a-modal :open="previewVisible" :title="previewTitle" :footer="null" @cancel="handleCancel">
        <img alt="example" style="width: 100%" :src="previewImage" />
        </a-modal>
    </div>
</template>

<script setup lang="ts">
import { message, Upload } from 'ant-design-vue';
import { PlusOutlined } from '@ant-design/icons-vue';
import type { UploadProps, UploadFile, UploadChangeParam } from 'ant-design-vue';
import type { RcFile as OriRcFile } from 'ant-design-vue/lib/vc-upload/interface';
interface FileType extends OriRcFile { readonly lastModifiedDate: Date; }

const props = defineProps({
    value: {
        type: Array as PropType<UploadProps['fileList']>,
        default: () => [],
    },
    maxCount: {
        type: Number,
        default: 1,
    }
});

const emit = defineEmits(['change']); // 抛出子组件事件

const previewVisible = ref(false);
const previewImage = ref('');
const previewTitle = ref('');

const fileList = ref<UploadProps['fileList']>([]);

watchEffect(() => {
    fileList.value = props.value;
});

/**
 * 将文件转换为Base64编码的字符串
 *
 * @param file 要转换的文件对象
 * @returns 返回一个Promise，resolve时携带Base64编码的字符串，reject时携带错误信息
 */
const getBase64 = (file: UploadFile) => {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.readAsDataURL((file as unknown as File));
        reader.onload = () => resolve(reader.result);
        reader.onerror = error => reject(error);
    });
}

const handleCancel = () => {
    previewVisible.value = false;
    previewTitle.value = '';
};

const handlePreview = async (file: UploadFile) => {
    if (!file.url && !file.preview) {
        file.preview = (await getBase64((file?.originFileObj as FileType))) as string;
    }
    previewImage.value = file.url || file.preview || '';
    previewVisible.value = true;
    previewTitle.value = file.name || (file?.url as string).substring((file?.url as string).lastIndexOf('/') + 1) || '';
};

const handleChange = ({ file, fileList }: UploadChangeParam) => {
    emit('change', fileList, file);
};

const beforeUpload: UploadProps['beforeUpload'] = file => {
    const isImage = file.type.indexOf('image') != -1;
    if (!isImage) {
        message.error('上传格式错误，请上传图片文件格式!');

        return isImage || Upload.LIST_IGNORE;
    }

    return false;
};

</script>

<style scoped>
.ant-upload-select-picture-card i {
    font-size: 32px;
    color: #999;
}

.ant-upload-select-picture-card .ant-upload-text {
    margin-top: 8px;
    color: #666;
}
</style>